﻿using System;
using System.Data;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
using MySql.Data.MySqlClient;

class HTMLExporter
{
	// Conversion parameters.
	string WikiBaseURL = null;
	string ExportListFilename = null;
	string OutputFilename = null;
	string ImageSrcPrefix = null;
	string ImageDestPrefix = null;

	public ArrayList BreakOutParms(string Text)
	{
		ArrayList WorkingSectionList;
		bool inQuote;
		string WorkingText;

		Text = Text + " ";
		// Make sure we break at end
		WorkingText = "";
		inQuote = false;
		WorkingSectionList = new ArrayList();

		// Iterate through and break based on whitespaces, sans quoted things.
		foreach ( char ch in Text) {
			// Toggle for quotes.
			if ((ch == '\"'))
			{
				inQuote = !inQuote;
			}
			else
			{
				// In a quote - just copy chars over to the result.
				if ((inQuote))
				{
					WorkingText = WorkingText + ch;
				}
				// Break on a whitespace.
				else
				{
					if ((char.IsWhiteSpace(ch)))
					{
						WorkingSectionList.Add(WorkingText.Trim());
						WorkingText = "";
					}
					else
					{
						WorkingText = WorkingText + ch;
					}

				}

			}
		}
		return WorkingSectionList;

		// Return our split text.
	}

	public void MainExportProcess()
	{
		// Let's do this thing!
		System.Console.WriteLine("--------------------------------------------");
		System.Console.WriteLine("Export time: " + System.DateTime.Now.ToString());
		System.Console.WriteLine("--------------------------------------------");
		System.Console.WriteLine();

		// Read in the article list.
		ArrayList articleList = new ArrayList();
		StreamReader re = File.OpenText(this.ExportListFilename);
		string thisLine = null;
		while ((thisLine = re.ReadLine()) != null)
		{
			if (thisLine.Trim() != "")
			{
				articleList.Add(thisLine);
			}
		}
		re.Close();

		// Export!
		PerformExport(articleList);
	}

	public static string GetStringLeft(string val, int charCount)
	{
		if (val.Length > charCount)
			return val.Substring(0, charCount);
		else
			return val;
	}

	public static string GetStringRight(string val, int charCount)
	{
		if (val.Length > charCount)
			return val.Substring(val.Length - charCount, charCount);
		else
			return val;
	}

	public static String getWebPage(String url, int timeout)
	{
		// used to build entire input
		StringBuilder sb = new StringBuilder();

		// used on each read operation
		byte[] buf = new byte[8192];

		// prepare the web page we will be asking for
		HttpWebRequest request = (HttpWebRequest)
			WebRequest.Create(url);
		request.Timeout = timeout;

		// execute the request
		HttpWebResponse response = (HttpWebResponse)
			request.GetResponse();

		// we will read data via the response stream
		Stream resStream = response.GetResponseStream();

		string tempString = null;
		int count = 0;

		do
		{
			// fill the buffer with data
			count = resStream.Read(buf, 0, buf.Length);

			// make sure we read some data
			if (count != 0)
			{
				// translate from bytes to ASCII text
				tempString = Encoding.ASCII.GetString(buf, 0, count);

				// continue building the string
				sb.Append(tempString);
			}
		}
		while (count > 0); // any more data to read?

		// return page source
		return sb.ToString();
	}

	public void PerformExport(ArrayList articleList)
	{
		// Open our output file.
		FileInfo file = new FileInfo(this.OutputFilename);
		StreamWriter outStream = file.CreateText();

		// Boilerplate stuff.
		outStream.WriteLine("<body>");

		// Iterate over each article.
		bool firstArticle = true;
		foreach (String articleName in articleList)
		{
			String normalizedArticleName = articleName.Trim().Replace(" ", "_");

			// Ignore single-letter titles and ones with "cont." embedded.
			// These rules accommodate copy-and-paste from the Category screens.
			if ((normalizedArticleName.Trim().Length == 1) ||
				(normalizedArticleName.ToLower().IndexOf("cont.") >= 0))
			{
				continue;
			}

			// Get the article HTML.
			System.Console.WriteLine("Exporting: " + normalizedArticleName);
			String articleURL = this.WikiBaseURL + "?title=" + normalizedArticleName;
			String rawWikiHTML = getWebPage(articleURL, 60000);

			// Hack out the body.
			String divText = "<div id=\"mainContent\">";
			int mainContentPos = rawWikiHTML.IndexOf(divText);
			if (mainContentPos >= 0)
			{
				String mainStuff = rawWikiHTML.Substring(mainContentPos + divText.Length);
				mainStuff = mainStuff.Replace("<div id=\"contentSub\"></div>", "");

				// Remove the TOC, if any.
				int tocPos = mainStuff.IndexOf("<table id=\"toc\"");
				if (tocPos >= 0)
				{
					int endTOCPos = mainStuff.IndexOf("</table", tocPos);

					if (endTOCPos > 0)
					{
						int endTableTagPos = mainStuff.IndexOf(">", endTOCPos);

						String leftOf = mainStuff.Substring(0, tocPos);
						String rightOf = mainStuff.Substring(endTableTagPos + 1);
						mainStuff = leftOf + rightOf;
					}
				}

				// Hack out the main body between the divs.
				int nextDivPos = mainStuff.IndexOf("</div><!-- end of MAINCONTENT div -->");
				if (nextDivPos >= 0)
				{
					mainStuff = mainStuff.Substring(0, nextDivPos);
				}

				// Hack out the "retrieved from" trailer.
				int rfPos = mainStuff.LastIndexOf("Retrieved from \"");
				if (rfPos >= 0)
				{
					mainStuff = mainStuff.Substring(0, rfPos);
				}

				// Remove links.
				int hyperPos;
				while ((hyperPos = mainStuff.IndexOf("<a")) >= 0)
				{
					int endHyperPos = mainStuff.IndexOf(">", hyperPos);

					if (endHyperPos > 0)
					{
						String leftOf = mainStuff.Substring(0, hyperPos);
						String rightOf = mainStuff.Substring(endHyperPos + 1);
						mainStuff = leftOf + rightOf;
					}
				}

				// Remove the "From IT Wiki" prefix.
				int introPos = mainStuff.IndexOf("<h3 id=\"siteSub\">");
				if (introPos >= 0)
				{
					int endIntroPos = mainStuff.IndexOf("</h3>", introPos);

					if (endIntroPos > 0)
					{
						int endIntroTagPos = mainStuff.IndexOf(">", endIntroPos);

						String leftOf = mainStuff.Substring(0, introPos);
						String rightOf = mainStuff.Substring(endIntroTagPos + 1);
						mainStuff = leftOf + rightOf;
					}
				}

				// Replace image prefixes of asked.
				if ((this.ImageSrcPrefix != null) && (this.ImageDestPrefix != null))
				{
					mainStuff = mainStuff.Replace(this.ImageSrcPrefix, this.ImageDestPrefix);
				}

				// Other stuff.
				mainStuff = mainStuff.Replace("[edit]", "");
				mainStuff = mainStuff.Replace("<div class=\"editsection\" style=\"float:right;margin-left:5px;\">[edit</a>]</div>", "");

				// Trim out spaces.
				mainStuff = mainStuff.Replace("\0", "");
				mainStuff = mainStuff.Trim();

				// Dump to the console.
				if (!firstArticle)
				{
					outStream.WriteLine("<hr>");
				}

				outStream.WriteLine(mainStuff);

				firstArticle = false;
			}
		}

		// Boilerplate stuff.
		outStream.WriteLine("</body>");

		// Cleanup.
		outStream.Close();
	}

	public static void Main(string[] ArgList)
	{
		System.Console.WriteLine();

		System.Console.WriteLine("=======================================================================");
		System.Console.WriteLine("WikiAutoLink CrossLink Generator - For MediaWiki");
		System.Console.WriteLine("Version 1.0a");
		System.Console.WriteLine("=======================================================================");
		System.Console.WriteLine();

		bool showHelp;
		if (ArgList.Length == 0) 
		{
			showHelp = true;
		}
		else if ((ArgList.Length == 1) && (ArgList[0] == "/?"))
		{
			showHelp = true;
		}
		else
		{
			showHelp = false;
		}

		if (showHelp)
		{
			System.Console.WriteLine("Exports a set of articles in HTML format.");
			System.Console.WriteLine();
			System.Console.WriteLine("Usage:");
			System.Console.WriteLine("WikiHTMLExport");
			System.Console.WriteLine("  [/wikibaseurl xxxx]    - Base URL to the wiki (minus '&title=xxx')");
			System.Console.WriteLine("  [/articlelist xxxx]    - File containing the list of articles to export");
			System.Console.WriteLine("  [/outputfile xxxx]     - To which HTML output it to be written");
			System.Console.WriteLine("  [/imagesrcprefix xxxx] - Prefix for images to be replaced");
			System.Console.WriteLine("  [/imagedstprefix xxxx] - Prefix with with to replace");
			System.Console.WriteLine();
			System.Console.WriteLine("Example:");
			System.Console.WriteLine("WikiHTMLExport /wikibaseurl http://wikirs/itwiki/index.php /articlelist ExportList.txt");
		}
		else
		{
			try 
			{
				// Construct our linker instance.
				HTMLExporter exporter = new HTMLExporter();

				// Parse the argument list.  Iterate over each parm.
				System.Console.WriteLine("[Debug]");
				string NextParm = null;
				foreach ( string Arg in ArgList) 
				{
					System.Console.WriteLine("Arg=" + Arg);

					// See if the value is second part of a tagged one.
					// The preceding parm has a  '/' prefix).
					if ((NextParm == "wikibaseurl"))
					{
						exporter.WikiBaseURL = Arg;
					}

					if ((NextParm == "articlelist"))
					{
						exporter.ExportListFilename = Arg;
					}

					if ((NextParm == "outputfile"))
					{
						exporter.OutputFilename = Arg;
					}

					if ((NextParm == "imagesrcprefix"))
					{
						exporter.ImageSrcPrefix = Arg;
					}

					if ((NextParm == "imagedstprefix"))
					{
						exporter.ImageDestPrefix = Arg;
					}

					NextParm = null;

					// look for prefixes and store what type for the next iteration.
					if (GetStringLeft(Arg, 1) == "/")
					{
						NextParm = GetStringRight(Arg, Arg.Length - 1);
					}
				}

				// Dump out our final config info for debugging purposes.
				System.Console.WriteLine("");
				System.Console.WriteLine("Wiki Base URL: " + exporter.WikiBaseURL);
				System.Console.WriteLine("Article List:  " + exporter.ExportListFilename);
				System.Console.WriteLine();

				// Convert away!
				exporter.MainExportProcess();
			}
			catch (Exception ex) 
			{
				System.Console.WriteLine();
				System.Console.WriteLine("Error!");
				System.Console.WriteLine(ex.Message);
				System.Console.WriteLine();
				System.Console.WriteLine(ex.StackTrace);
			}
		}
	}
}
